package com.chu.cloud.advice;

import com.chu.cloud.enums.ResultEnums;
import com.chu.cloud.response.ResponseMessage;
import com.chu.cloud.response.ResultVo;
import com.chu.cloud.util.ChuException;
import com.chu.cloud.util.JsonUtils;
import com.fasterxml.jackson.core.JsonParseException;
import feign.FeignException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;

/**
 * @Description: 全局异常拦截器 see {@link org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler}
 * @author: TianShu.CHU
 * @CreateDate: 2018-04-05 22:35
 * @Version: 1.0
 */
@RestControllerAdvice({"com.chu.cloud.api.controller","com.chu.cloud.controller"})
@Slf4j
public class GlobalExceptionHandler {

    /***包含有一个以上的中文文字表达式**/
    public static final String CONTAINS_CHINESE_REGEX = ".*[\\u4e00-\\u9fa5]+.*";


    /**
     * 拦截参数不合法错误异常
     *
     * @param e
     * @param req
     * @return
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<String> handlerMethodArgumentNotValidException(MethodArgumentNotValidException e, HttpServletRequest req) {
        String tips = "参数不合法";
        log.error("tips={},request method={},uri={},异常={}", tips, req.getMethod(), req.getRequestURI(), e);
        List<ObjectError> allErrors = e.getBindingResult().getAllErrors();
        tips = allErrors.get(0).getDefaultMessage();

        return new ResponseEntity<String>(tips, HttpStatus.BAD_REQUEST);
    }

    /**
     * 拦截断言异常
     *
     * @param e
     * @param req
     * @return
     */
    @ExceptionHandler(IllegalArgumentException.class)
    public ResponseEntity<String> handlerIllegalArgumentException(IllegalArgumentException e, HttpServletRequest req) {
        String tips = e.getMessage();
        log.error("tips={},request method={},uri={}", tips, req.getMethod(), req.getRequestURI());
        return new ResponseEntity<String>(tips, HttpStatus.BAD_REQUEST);
    }

    /**
     * 拦截自定义异常
     * 制定规范,需使用枚举
     * @param e
     * @return
     */
    @ExceptionHandler(ChuException.class)
    public ResponseMessage handlerChuException(ChuException e) {
        log.error("发生异常:",e);
        String message = e.getMessage();
        ResponseMessage response = new ResponseMessage(HttpStatus.INTERNAL_SERVER_ERROR.value(),message);
        try {
            ResultEnums resultEnums = JsonUtils.json2pojo(message, ResultEnums.class);
            return new ResponseMessage(resultEnums.getResponseCode(),resultEnums.getResponseMsg());
        } catch (Exception e1) {

        }

        return response;

    }

    /**
     * 拦截微服务抛出的异常
     * <p>
     * 1.主动抛出的Assert断言异常和ChuException异常;
     * 2.其他异常都会触发服务熔断 HystrixRuntimeException
     * 3.断言异常可能用不到,因为是restful风格,参数不允许null,如果是body对象参数则是@Valid校验400异常
     *  补充:
     *         断言异常会触发服务熔断,有熔断就不要使用Assert
     * </p>
     *
     * @param e feign.FeignException: status 500 reading IActivityFeignClient#add(ActivityDto); content:
     *          {"timestamp":1524636440847,"status":500,"error":"Internal Server Error","exception":"java.lang.IllegalArgumentException","message":"标题不能为空","path":"/v1/activity/"}
     *          <p>
     *          "feign.FeignException: status 500 reading IActivityFeignClient#add(ActivityDto);content:
     *          {\"timestamp\":1524636092126,\"status\":500,\"error\":\"Internal Server Error\",\"exception\":\"com.chu.cloud.util.ChuException\",\"message\":\"\\\"USER_NOT_VALID\\\"\",\"path\":\"/v1/activity/\"}";
     *          </p>
     * @return
     */
    @ExceptionHandler(FeignException.class)
    public Object handlerFeignException(FeignException e,HttpServletRequest req) {
        String tips = "微服务出异常了";
        String msg = e.getMessage();
        log.error("请求方法:{} 请求Uri:{},异常信息:{}",req.getMethod(), req.getRequestURI(), e);
        try {
            String errorContent = "content:";
            if (msg.contains(errorContent)) {
                msg = msg.substring(msg.indexOf(errorContent) + errorContent.length()).trim();
                Map<String, Object> errorMap = JsonUtils.json2map(msg);
                String errorMessage = (String) errorMap.get("message");
                String exceptionClass = (String) errorMap.get("exception");
                //抛出自定义异常
                if (ChuException.class.getName().equals(exceptionClass)) {
                    try{
                        ResultEnums resultEnums = JsonUtils.json2pojo(errorMessage, ResultEnums.class);
                        return ResultVo.errorOfEnum(resultEnums);
                    }catch (JsonParseException exc){
                        return ResultVo.errorOfMessage(errorMessage);
                    }
                } else if (IllegalArgumentException.class.getName().equals(exceptionClass)) {
                    return ResultVo.errorOfMessage(errorMessage);
                }
            }
        } catch (Exception ex) {
            log.error(tips, ex);
        }
        return ResultVo.errorOfMessage(tips);
    }

    /**
     * 拦截所有异常
     * @param e
     * @return
     */
    @ExceptionHandler(Exception.class)
    public ResultVo exceHandler(Exception e){
        log.error("异常信息:",e);
        return ResultVo.getError(HttpStatus.INTERNAL_SERVER_ERROR.value(),"服务内部出错了");
    }

}
